const fs = require("fs");
const path = require("path");
const https = require("https");
const URL = require("url").URL;

//当前配置数据
const conf = {
    //要压缩的图片集合
    files: [],
    //要处理的文件夹路径，默认当前路径
    EntryFolder: "./",
    dataJson: "./cache.json",
    //是否递归查找图片，
    isDeepLoop: true,
    //要处理的文件格式，图片文件
    Exts: [".jpg", ".png"],
    //最大处理的图片大小
    Max: 999999999999999999999999, // 5MB == 5242848.754299136
};
//指定创建目录及文件名称，__dirname为执行当前js文件的目录
var dataJsonFile = path.join(__dirname, conf.dataJson);

let url = process.argv[2];//获取想要的压缩的路径
conf.EntryFolder = url;
let currentIndex = 0;//当前压缩完成的下标
let data = {};//缓存
console.log('开始压缩');

readDataJson();
fileFilter(conf.EntryFolder)

// console.log("本次执行脚本的配置：", conf);
// console.log("等待处理文件的数量:", conf.files.length);

//读取缓存文件
function readDataJson () {
    try {
        fs.statSync(dataJsonFile);
        var result = JSON.parse(fs.readFileSync(dataJsonFile));
        data = result;
        // console.log(`有${conf.dataJson}`, data);
    } catch (error) {
        // console.log(`没有${conf.dataJson}文件，创建文件`);
        fs.writeFile(dataJsonFile, "", (err) => {
            if (err) {
                return console.log(err);
            }
            // console.log('文件创建成功，地址：' + dataJsonFile);
        });
    }
}

//遍历压缩
conf.files.forEach(img => {
    fileUpload(img)
});

//////////////////////////////// 工具函数

/**
 * string转为base64
 */
function stringToBase64 (str) {
    return new Buffer.from(str).toString("base64");
}

/**
 * base64转字符串
 */
function base64ToString (b64) {
    return new Buffer.from(b64, "base64").toString();
}

// 生成随机IP， 赋值给 X-Forwarded-For
function getRandomIP () {
    return Array.from(Array(4)).map(() => parseInt(Math.random() * 255)).join(".");
}

/**
 * 过滤待处理文件夹，得到待处理文件列表
 * @param {*} folder 待处理文件夹
 * @param {*} files 待处理文件列表
 */
function fileFilter (folder) {
    // fs.statSync(url).isDirectory()
    let url1 = path.normalize(folder);
    if (fs.statSync(url1).isDirectory()) {
        // 读取文件夹
        fs.readdirSync(folder).forEach(file => {
            let fullFilePath = path.join(folder, file)
            // 读取文件信息
            let fileStat = fs.statSync(fullFilePath);
            // 过滤文件安全性/大小限制/后缀名
            if (fileStat.size <= conf.Max && fileStat.isFile() && conf.Exts.includes(path.extname(file))) {
                // console.log('递归文件夹', fullFilePath);
                let str = stringToBase64(fullFilePath);
                let resData = data[str];
                if (resData) {
                    let lastSize = resData.endSize;
                    let currentSize = `${(fileStat.size / 1024).toFixed(2)}kb`;
                    if (lastSize === currentSize) {
                        console.log(`${fullFilePath}已经压缩过了了，跳过压缩`);
                    } else {
                        console.log(`${fullFilePath}已经压缩过了了，但和上次压缩大小不一样，可能替换了图片，没跟换名字，再次重复压缩`);
                        conf.files.push(fullFilePath);
                    }
                } else {
                    conf.files.push(fullFilePath);
                }

                // console.log(conf.files);
            } else if (conf.isDeepLoop && fileStat.isDirectory()) {
                // 是都要深度递归处理文件夹
                fileFilter(fullFilePath);
            }
        });
    } else {
        // 读取文件信息
        let fileStat = fs.statSync(folder);
        if (fileStat.size <= conf.Max && fileStat.isFile() && conf.Exts.includes(path.extname(folder))) {
            // console.log('递归文件夹', folder);
            conf.files.push(folder);
        }
    }
}

/**
 * TinyPng 远程压缩 HTTPS 请求的配置生成方法
 */
function getAjaxOptions () {
    return {
        method: "POST",
        hostname: "tinypng.com",
        path: "/web/shrink",
        headers: {
            "rejectUnauthorized": false,
            "X-Forwarded-For": getRandomIP(),
            "Postman-Token": Date.now(),
            "Cache-Control": "no-cache",
            "Content-Type": "application/x-www-form-urlencoded",
            "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
        }
    }
}

/**
 * TinyPng 远程压缩 HTTPS 请求
 * @param {string} img 待处理的文件
 * @success {
 *              "input": { "size": 887, "type": "image/png" },
 *              "output": { "size": 785, "type": "image/png", "width": 81, "height": 81, "ratio": 0.885, "url": "https://tinypng.com/web/output/7aztz90nq5p9545zch8gjzqg5ubdatd6" }
 *           }
 * @error  {"error": "Bad request", "message" : "Request is invalid"}
 */
function fileUpload (imgPath) {
    let req = https.request(getAjaxOptions(), (res) => {
        res.on("data", buf => {
            let obj = JSON.parse(buf.toString());
            if (obj.error) console.log(`压缩失败！\n 当前文件：${imgPath} \n ${obj.message}`);
            else fileUpdate(imgPath, obj);
        });
    });

    req.write(fs.readFileSync(imgPath), "binary");
    req.on("error", e => console.error(`请求错误! \n 当前文件：${imgPath} \n, e`));
    req.end();
}

// 该方法被循环调用,请求图片数据
function fileUpdate (entryImgPath, obj) {
    let options = new URL(obj.output.url);
    let req = https.request(options, res => {
        let body = "";
        res.setEncoding("binary");
        res.on("data", (data) => body += data);
        res.on("end", () => {
            // console.log(entryImgPath);
            fs.writeFile(entryImgPath, body, "binary", err => {
                if (err) return console.error(err);
                currentIndex += 1;
                let startSize = `${(obj.input.size / 1024).toFixed(2)}kb`;
                let endSize = `${(obj.output.size / 1024).toFixed(2)}kb`;
                let proportion = `${((1 - obj.output.ratio) * 100).toFixed(2)}%`
                let log =
                    `${currentIndex}/${conf.files.length}压缩成功，优化比例: ${proportion}，
                    原始大小: ${startSize}，
                    压缩大小: ${endSize},
                    文件：${entryImgPath}
                    `;
                console.log(log);
                let resData = {
                    "url": entryImgPath,
                    "proportion": proportion,
                    "startSize": startSize,
                    "endSize": endSize
                };

                let str = stringToBase64(entryImgPath);
                data[str] = resData;
                // console.log("值", data[entryImgPath], "路径", entryImgPath, "总值", data);
                if (currentIndex == conf.files.length) {
                    compressOver();
                }
            });


        });
    });
    req.on("error", e => console.error(e));
    req.end();
}

//压缩完毕
function compressOver () {
    //把data对象转换为json格式字符串
    var content = JSON.stringify(data);
    //写入文件
    fs.writeFile(dataJsonFile, content, (err) => {
        if (err) {
            return console.log(err);
        }
        console.log('压缩完毕');
    });
}